package games.mapacman.server;

import games.mapacman.client.*;
import games.mapacman.common.Constants;
import java.io.IOException;
import java.net.Proxy;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import marauroa.client.BannedAddressException;

import marauroa.client.ClientFramework;
import marauroa.client.LoginFailedException;
import marauroa.client.TimeoutException;
import marauroa.client.net.PerceptionHandler;
import marauroa.common.Log4J;
import marauroa.common.game.Perception;
import marauroa.common.game.RPObject;
import marauroa.common.net.InvalidVersionException;
import marauroa.common.net.message.MessageS2CMigrate;
import marauroa.common.net.message.MessageS2CPerception;
import marauroa.common.net.message.MessageS2SInSync;
import marauroa.common.net.message.TransferContent;

public class DummyAgent extends ClientFramework implements Runnable {

    private static final marauroa.common.Logger logger = Log4J.getLogger(DummyAgent.class);
    private static final String LOG4J_PROPERTIES = "games/mapacman/log4j.properties";
    private DummyAgentPerceptionHandler phandler;
    private Map<RPObject.ID, RPObject> world_objects;
    private Map<RPObject.ID, RPObject> wall_objects;
    private Vector<RPObject> players;
    private Vector<RPObject> ghosts;
    private Vector<RPObject> dots;
    private MaPacmanGui GUI;
    private boolean running;
    private boolean migrating;
    private GameScreen screen;
    private String user;
    private String pass;
    private String server;
    private int port;
    protected String currentZone = "";
    private Thread thread = null;

//	void sendChatMsg(String text) {
//		RPAction action = new RPAction();
//		action.put("type", Constants.CHATMESSAGE);
//		action.put("content", text);
//		this.send(action);
//	}
//
//	void changeDirection(int dir) {
//		RPAction action = new RPAction();
//		action.put("type", Constants.CHANGEDIR);
//		action.put("content", dir);
//		try{
//                    this.send(action);
//                    startTimer = System.currentTimeMillis();
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//	}
    public void initialize() {
        players = new Vector<RPObject>();
        ghosts = new Vector<RPObject>();
        dots = new Vector<RPObject>();
        running = true;
        migrating = false;
        world_objects = new HashMap<RPObject.ID, RPObject>();
        wall_objects = new HashMap<RPObject.ID, RPObject>();

        phandler = new DummyAgentPerceptionHandler(new DummyAgentPerceptionListener(this,
                wall_objects, ghosts, players));
    }

    public DummyAgent(boolean logging, String username, String password,
            String Server, int port) {
        super(LOG4J_PROPERTIES);

        initialize();
        setGameOptions(username, password, Server, port);
        thread = new Thread(this);
        thread.start();
    }

    public void startGame(String username, String password, String Server,
            int port) {
        try {
            //GUI.printText("Trying to login to " + Server + ":" + port);
            this.connect(Server, port);
            this.login(username, password);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
            }
            gameLoop();
            this.logout();
        } catch (IOException ex) {
            Logger.getLogger(DummyAgent.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidVersionException ex) {
            Logger.getLogger(DummyAgent.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimeoutException ex) {
            Logger.getLogger(DummyAgent.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BannedAddressException ex) {
            Logger.getLogger(DummyAgent.class.getName()).log(Level.SEVERE, null, ex);
        } catch (LoginFailedException e) {
            //GUI.ErrorMsg("seems like login didn't work :(");
            e.printStackTrace();
            try {
                this.logout();
            } catch (Exception e2) {
                logger.error("Logout failed");
                e2.printStackTrace();
            }
        }

    }

    public DummyAgent(boolean logging) {
        super(LOG4J_PROPERTIES);
        initialize();
    }

    public void gameLoop() {
        long fpstimer = System.currentTimeMillis();
        long fpscounter = 0;
        //screen.setPlayerGhostVector(players, ghosts);

        // time of 1 turn in ms. Should be 400 but needs to be adjusted for slow
        // PCs
        int estTurntime = 400;

        double sleeptime = 0;
        running = true;
        while (running) {
            fpscounter++;
            long currentTime = System.currentTimeMillis();

            try {
                this.loop(0);
            } catch (Exception e) {
                System.err.println("exception in loop");
                e.printStackTrace();
            }

            // in 1 turntime 5fps should be made ...
            sleeptime = 1000 / ((1000 / estTurntime) * 5)
                    - (System.currentTimeMillis() - currentTime);

            if (sleeptime < 1.0) {
                sleeptime = 1;
            }
            Random random = new Random(System.currentTimeMillis());
            try {
                Thread.sleep((int) sleeptime);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.err.println("exception not loop");
            }
            if ((System.currentTimeMillis() - fpstimer) > 1000) {
                fpstimer = System.currentTimeMillis();
                fpscounter = 0;
            }
        }

    }

    @Override
    protected void onPerception(MessageS2CPerception message) {

        if (message.getPerceptionType() == Perception.SYNC) {
        }
        try {
            if (!migrating) {
                phandler.apply(message, world_objects);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    protected boolean migrate(String host) {
        screen.clear();
        players.clear();
        ghosts.clear();
        wall_objects.clear();
        dots.clear();
        this.server = host;
        try {
            this.logout();
        } catch (InvalidVersionException ex) {
            Logger.getLogger(DummyAgent.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimeoutException ex) {
            Logger.getLogger(DummyAgent.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BannedAddressException ex) {
            Logger.getLogger(DummyAgent.class.getName()).log(Level.SEVERE, null, ex);
        }
        this.stopGame();
        return true;
    }

    @Override
    protected List<TransferContent> onTransferREQ(List<TransferContent> items) {
        return items;
    }

    @Override
    protected void onTransfer(List<TransferContent> items) {
    }

    @Override
    protected void onAvailableCharacters(String[] characters) {

        try {
            if (chooseCharacter(characters[0])) {
//				GUI.printText("logged in as " + characters[0]);
            }
//			screen.setPlayerName(characters[0]);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onServerInfo(String[] info) {
    }

    @Override
    protected String getGameName() {
        return Constants.GAMENAME;
    }

    @Override
    protected String getVersionNumber() {
        return Constants.VERSION;
    }

    @Override
    public void close() {
        GUI.setVisible(false);
        running = false;
    }

    public void run() {
        //System.err.println(user + " " + pass+" "+server+" "+port);
        startGame(user, pass, server, port);
    }

    public void setGameOptions(String username, String password, String server,
            int port) {
        this.user = username;
        this.pass = password;
        this.server = server;
        this.port = port;

    }

    public void stopGame() {
        running = false;

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //System.exit(1);

    }

    @Override
    protected void onPreviousLogins(List<String> previousLogins) {
        //System.out.println("Previous logins: " + previousLogins.toString());
    }

    @Override
    public synchronized void sendSyncConfirmS2S() {
        this.getNetMan().addMessage(new MessageS2SInSync());
    }

    @Override
    public synchronized void onMigrate(MessageS2CMigrate msg) {
        migrating = true;
        ZoneDivider.get().setSynced(true);
        if (!MaPacmanRPWorld.get().shouldStart) {
            MaPacmanRPWorld.get().shouldStart = true;
        }


    }
}
